#ifndef __CLX_DATA_HPP__
#define __CLX_DATA_HPP__

#include <unordered_map>
#include <pthread.h>
#include "util.hpp"
#include "config.hpp"

namespace clx_cloud {
    struct BackupInfo {
  	    bool NewBackupInfo(const std::string realpath) {
            Config*  config = Config::GetInstance();
            clx_cloud::FileUtil fu(realpath);
            if (fu.Exists() == false) {
                std::cout << "new backupinfo file not exists" << std::endl;
                return false;
            }
            this->pack_flag = false;
            this->fsize = fu.FileSize();
            this->atime = fu.LastATime();
            this->mtime = fu.LastMTime();
            this->real_path = realpath;

            std::string pack_dir = config->GetPackDir();
            std::string pack_suffix = config->GetPackFileSuffix();
            this->pack_path = pack_dir + fu.FileName() + pack_suffix;

            std::string download_prefix = config->GetDownloadPrefix();
            this->url_path = download_prefix + fu.FileName();
            return true;
        }
		bool pack_flag; // 是否压缩标志
		size_t fsize; 
		time_t atime;
		time_t mtime;
		std::string real_path; // 文件实际存储路径
		std::string pack_path; // 压缩包存储路径名称
		std::string url_path;  // URL
    };

    class DataManager {
		public:
            DataManager() {
                _backup_file = Config::GetInstance()->GetBackupFile();
                pthread_rwlock_init(&_rwlock, NULL);
                InitLoad();
            }
            ~DataManager() {
                pthread_rwlock_destroy(&_rwlock);
            }
            bool Storage() {
                // 1、获取所有数据
                std::vector<BackupInfo> array;
                this->GetAll(&array);
                // 2、添加到Json Value
                Json::Value root;
                for (int i = 0; i < array.size(); i++) {
                    Json::Value item;
                    item["pack_flag"] = array[i].pack_flag;
                    item["fsize"] = static_cast<Json::Value::Int64>(array[i].fsize);
                    item["atime"] = static_cast<Json::Value::Int64>(array[i].atime);
                    item["mtime"] = static_cast<Json::Value::Int64>(array[i].mtime);
                    item["real_path"] = array[i].real_path;
                    item["pack_path"] = array[i].pack_path;
                    item["url_path"] = array[i].url_path;
                    root.append(item); // 添加数组元素
                }
                // 3、对Json::Value 序列化
                std::string body;
                JsonUtil::Serialize(root, &body);
                // 4、写文件
                FileUtil fu(_backup_file);
                fu.SetContent(&body);
                return true;
            }                          // 每次数据新增或者修改都需要重新持久化存储，避免数据丢失

            bool InitLoad() {          // 初始化加载，在每次系统重启都要加载以前的数据
                // 1、将数据从_backup_file中读取出来
                FileUtil fu(_backup_file);
                if (fu.Exists() == false) {
                    return true;
                }
                std::string body;
                fu.GetContent(&body);
                // 2、反序列化
                Json::Value root;
                JsonUtil::UnSerialize(body, &root);
                // 3、将反序列化得到的Json::Value中的数据添加到table
                for (int i = 0; i < root.size(); i++) {
                    BackupInfo info;
                    info.pack_flag = root[i]["pack_flag"].asBool();
                    info.fsize = root[i]["fsize"].asInt();
                    info.atime = root[i]["atime"].asInt();
                    info.mtime = root[i]["mtime"].asInt();
                    info.pack_path = root[i]["pack_path"].asString();
                    info.real_path = root[i]["real_path"].asString();
                    info.url_path  = root[i]["url_path"].asString();
                    Insert(info);
                }
                return true;
            } 
            bool Insert(const BackupInfo &info) {    // 新增
                pthread_rwlock_wrlock(&_rwlock);
                _table[info.url_path] = info;
                pthread_rwlock_unlock(&_rwlock);
                Storage();
                return true;
            }
            bool Update(const BackupInfo &info) {   // 修改
                pthread_rwlock_wrlock(&_rwlock);
                _table[info.url_path] = info;
                pthread_rwlock_unlock(&_rwlock);
                Storage();
                return true;
            }   
           
            bool GetOneByUrl(const std::string &url, BackupInfo *info) {
                pthread_rwlock_wrlock(&_rwlock);
                auto it = _table.find(url);
                if (it == _table.end()) {
                    pthread_rwlock_unlock(&_rwlock);
                    return false;
                }
                *info = it->second;
                pthread_rwlock_unlock(&_rwlock);
                return true;
            }
            bool GetOneByRealpath(const std::string &realpath, BackupInfo *info) {
                pthread_rwlock_wrlock(&_rwlock);
                for (auto it = _table.begin(); it != _table.end(); it++) {
                    if (it->second.real_path == realpath) {
                        *info = it->second;
                        pthread_rwlock_unlock(&_rwlock);
                        return true;
                    }
                }
                pthread_rwlock_unlock(&_rwlock);
                return false;
            }
            bool GetAll(std::vector<BackupInfo> *array) {
                pthread_rwlock_wrlock(&_rwlock);
                for (auto it = _table.begin(); it != _table.end(); it++) {
                    array->push_back(it->second);
                }
                pthread_rwlock_unlock(&_rwlock);
                return true;
            }
		private:
			std::string _backup_file; // 持久化存储文件
			std::unordered_map<std::string, BackupInfo> _table; // 内存中以hash表存储
			pthread_rwlock_t _rwlock; // 读写锁
    };
}

#endif
